#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdbool.h>
#include <poll.h>
#include <signal.h>

#define INFTIM -1
#define SERVER_PORT 8888
#define SERVER_ADDR "127.0.0.1"
#define RECV_BUF_SIZE 1024
#define SEND_BUF_SIZE 1024
#define EXIT_STRING_CMD "exit"

void *thread_recv_for_server(void *argv)
{
    struct pollfd sock_pollfd;
    int poll_listen_count;
    int read_recv_buf_count;
    char recv_buf[RECV_BUF_SIZE + 1] = {0};

    /* init */
    sock_pollfd.fd = *((int *)argv);
    sock_pollfd.events = POLLIN;

    // poll listen
    while (true)
    {
        poll_listen_count = poll(&sock_pollfd, 1, INFTIM); /* Can't timeout. */
        if (poll_listen_count == -1 ||
            poll_listen_count == 0)
        {
            perror("poll() error: ");
            exit(EXIT_FAILURE);
        }
        if (sock_pollfd.revents != POLLIN) // 如果监听到的不是可读事件，则退出
        {
            printf("other error.\n");
            exit(EXIT_FAILURE);
        }

        // listened
        printf("server: ");
        read_recv_buf_count = read(sock_pollfd.fd, recv_buf, RECV_BUF_SIZE);
        if (read_recv_buf_count == -1)
        {
            perror("read() error: ");
            exit(EXIT_FAILURE);
        }
        // 如果收到退出指令字符串就退出
        if (strstr(recv_buf, EXIT_STRING_CMD) != NULL)
        {
            printf("chat to close.\n");
            exit(EXIT_SUCCESS);
        }
        printf("%s", recv_buf);
        bzero(recv_buf, RECV_BUF_SIZE);
    }
}

int main(int argc, char *argv[])
{
    struct sockaddr_in serveraddr;
    int sockfd;
    pthread_t pthread_recv_tid;
    char send_buf[SEND_BUF_SIZE + 1] = {0};

    sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sockfd == -1)
    {
        perror("new socket error: ");
        exit(EXIT_FAILURE);
    }

    /* init serveraddr */
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(SERVER_PORT);
    if (inet_pton(AF_INET, SERVER_ADDR, &serveraddr.sin_addr) < 0)
    {
        perror("inet_pton() error for %s: \n");
        exit(EXIT_FAILURE);
    }

    /* start connect server */
    if (connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    {
        perror("connect() error: ");
        exit(EXIT_FAILURE);
    }
    printf("connect to server succeed.\n");

    /* start chat */
    printf("start chat:\n");
    pthread_create(&pthread_recv_tid, NULL, thread_recv_for_server, &sockfd);
    while (true)
    {
        if (fgets(send_buf, SEND_BUF_SIZE, stdin) != NULL)
        {
            write(sockfd, send_buf, strlen(send_buf));
            if (strstr(send_buf, EXIT_STRING_CMD) != NULL)
            {
                printf("chat to close.\n");
                exit(EXIT_SUCCESS);
            }
            bzero(send_buf, SEND_BUF_SIZE);
        }
    }
    return 0;
}
